package com.youngjun.common.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;

/**
 * @author YoungJun
 */
public class JsonUtils {

    private static final ObjectMapper objectMapper = new ObjectMapper() {{
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
    }};

    private static final ObjectMapper objectMapperAcceptCaseInsensitive = new ObjectMapper() {{
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
        configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
    }};

    private static final ObjectMapper objectMapperPropertyNamingStrategy = new ObjectMapper(){{
        setPropertyNamingStrategy(new CustomPropertyNamingStrategy());
        enable(SerializationFeature.INDENT_OUTPUT);
    }};
    private static final ObjectMapper objectMapperPropertyNamingStrategyNonEmpty= new ObjectMapper(){{
        setPropertyNamingStrategy(new CustomPropertyNamingStrategy());
        enable(SerializationFeature.INDENT_OUTPUT);
        setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    }};

    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }


    public static ObjectMapper getObjectMapperAcceptCaseInsensitive() {
        return objectMapperAcceptCaseInsensitive;
    }

    public static ObjectMapper getObjectMapperPropertyNamingStrategy() {
        return objectMapperPropertyNamingStrategy;
    }

    public static ObjectMapper getObjectMapperPropertyNamingStrategyNonEmpty() {
        return objectMapperPropertyNamingStrategyNonEmpty;
    }

    static class CustomPropertyNamingStrategy extends PropertyNamingStrategy {
        @Override
        public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
            return convert(field.getName());
        }

        @Override
        public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
            return convert(method.getName().toString());
        }

        @Override
        public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
            return convert(method.getName().toString());
        }

        private String convert(String input) {
            return input.substring(3);
        }
    }

}

